﻿package com.crl.module.logging.targets
{
	import com.crl.module.logging.LoggerLevel;
	import com.crl.module.logging.events.LoggerEvent;
    
    /**
     * All logger target implementations that have a formatted line style output should extend this class. It provides default behavior for including date, time, channel, and level within the output.
     */
    public class LineFormattedTarget extends CoreLoggerTarget
    {
        
        /**
         * Creates a new LineFormattedTarget instance.
         */
        public function LineFormattedTarget()
        {
            super();
        }
        
        /**
         * Indicates if the channel for this target should added to the trace.
         */
        public var includeChannel:Boolean ;
        
        /**
         * Indicates if the date should be added to the trace.
         */
        public var includeDate:Boolean ;
        
        /**
         * Indicates if the level for the event should added to the trace.
         */
        public var includeLevel:Boolean ;
        
        /**
         * Indicates if the line for the event should added to the trace.
         */
        public var includeLines:Boolean ;
        
        /**
         * Indicates if the milliseconds should be added to the trace. Only relevant when includeTime is <code class="prettyprint">true</code>.
         */
        public var includeMilliseconds:Boolean ;
        
        /**
         * Indicates if the time should be added to the trace.
         */
        public var includeTime:Boolean ;
        
        /**
         * The separator string.
         */
        public var separator:String = " " ;
        
        /**
         * Descendants of this class should override this method to direct the specified message to the desired output.
         * @param message String containing preprocessed log message which may include time, date, channel, etc. 
         * based on property settings, such as <code class="prettyprint">includeDate</code>, <code class="prettyprint">includeChannel</code>, etc.
         */
        public function internalLog( message:* , level:LoggerLevel ):void
        {
            // override this method.
        }
        
        /**
         *  This method handles a <code class="prettyprint">LoggerEvent</code> from an associated logger.
         *  A target uses this method to translate the event into the appropriate format for transmission, storage, or display.
         *  This method will be called only if the event's level is in range of the target's level.
         */
        public override function logEvent( event:LoggerEvent ):void
        {
            var message:*      = event.message ;
            var level:String   = LoggerEvent.getLevelString( event.level ) ;
            var channel:String = event.currentTarget.channel ;
            message= formatMessage( message, level, channel , new Date() ) ;
            internalLog( message , event.level ) ;
        }
        
        /**
         * Resets the internal line number value (set to 1).
         */
        public function resetLineNumber():void 
        {
            _lineNumber = 1 ; 
        }
        
        /**
         * This method format the passed Date in arguments.
         */
        protected function formatDate( d:Date ):String 
        {
            var date:String = "" ;
            date += getDigit(d.getDate()) ;
            date += "/" + getDigit(d.getMonth() + 1) ;
            date += "/" + d.getFullYear();
            return date ;
        }
        
        /**
         * This method format the passed level in arguments.
         */
        protected function formatLevel(level:String):String 
        {
            return '[' + level + ']' ;
        }
        
        /**
         * This method format the current line value.
         */
        protected function formatLines():String 
        {
            return "[" + _lineNumber++ + "]" ; 
        }
        
        /**
         * This method format the log message.
         */
        protected function formatMessage( message:* , level:String , channel:String , date:Date ):String 
        {
            var msg:String = "" ;
            var d:Date = date || new Date ;
            if (includeLines) 
            {
                msg += formatLines() + separator ;
            }
            if (includeDate) 
            {
                msg += formatDate(d) + separator ;
            }
            if (includeTime) 
            {
                msg += formatTime(d) + separator ;
            }
            if (includeLevel)
            {
                msg += formatLevel(level || "" ) + separator ;
            } 
            if ( includeChannel ) 
            {
                msg += ( channel || "" ) + separator ;
            }
            msg += message.toString() ;
            return msg ;
        }
        
        /**
         * This method format the current Date passed in argument.
         */
        protected function formatTime( d:Date ):String 
        {
            var time:String = "" ;
            time += getDigit(d.getHours()) ;
            time += ":" + getDigit(d.getMinutes()) ;
            time += ":" + getDigit(d.getSeconds()) ;
            if( includeMilliseconds ) 
            {
                time += ":" + getDigit( d.getMilliseconds() ) ;
            }
            return time ;
        }
        
        /**
         * Returns the string representation of a number and use digit conversion.
         * @return the string representation of a number and use digit conversion.
         */
        protected function getDigit(n:Number):String 
        {
            if ( isNaN(n) ) 
            {
                return "00" ;
            }
            return ((n < 10) ? "0" : "") + n ;
        }
        
        /**
         * @private
         */
        private var _lineNumber:uint = 1 ;
    }
}